/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.pig4cloud.pig.ads.service.impl;

import cn.hutool.core.lang.Pair;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pig.ads.pig.mapper.AdCreativeMaterialMapper;
import com.pig4cloud.pig.ads.pig.mapper.AdMaterialPlatformMapper;
import com.pig4cloud.pig.ads.service.AdCreativeMaterialService;
import com.pig4cloud.pig.ads.service.AdvCreativeServiceDetailService;
import com.pig4cloud.pig.api.entity.AdCreativeMaterialEntity;
import com.pig4cloud.pig.api.entity.AdMaterialPlatform;
import com.pig4cloud.pig.api.entity.TtCreativeDetail;
import com.pig4cloud.pig.api.gdt.entity.GdtAd;
import com.pig4cloud.pig.common.core.constant.enums.PlatformTypeEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 素材同步平台信息表
 *
 * @author pigx code generator
 * @date 2021-06-23 14:32:25
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AdCreativeMaterialServiceImpl extends ServiceImpl<AdCreativeMaterialMapper, AdCreativeMaterialEntity> implements AdCreativeMaterialService {

//	private static final Integer TT_MATERIAL_FLAG = 1;
//	private static final Integer GDT_MATERIAL_FLAG = 8;
//	private final AdvCreativeServiceDetailService advCreativeServiceDetailService;

	private final AdMaterialPlatformMapper adMaterialPlatformMapper;

	/**
	 * 批量保存或更新巨量引擎创意与素材关系
	 *
	 * @param creativeDetailList
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public void batchUpsertOeCreativeMaterial(List<TtCreativeDetail> creativeDetailList) {
		if (CollectionUtils.isEmpty(creativeDetailList)) {
			return;
		}
		final Integer platformId = Integer.parseInt(PlatformTypeEnum.TT.getValue());

		final Map<Long, Set<String>> advertiserIdMapping = new HashMap<>();
		final List<AdCreativeMaterialEntity> creativeMaterialList = new ArrayList<>();

		for (TtCreativeDetail creativeDetail : creativeDetailList) {
			final Long advertiserId = Long.parseLong(creativeDetail.getAdvertiserId()), adId = Long.parseLong(creativeDetail.getAdId());
			final Set<String> platformFileIds = advertiserIdMapping.computeIfAbsent(advertiserId, (key) -> new HashSet<>());

			// 解析头条媒体平台落地页ID
			final Long landingPageId = this.parseOeLandingPageId(StringUtils.isNotBlank(creativeDetail.getExternalUrl()) ? creativeDetail.getExternalUrl() : creativeDetail.getWebUrl());

			// 解析头条媒体平台素材文件ID
			final JSONArray creatives = JSON.parseArray(creativeDetail.getCreativeList());
			for (int i = 0; i < creatives.size(); ++i) {
				final JSONObject creative = creatives.getJSONObject(i);

				final Long creativeId = creative.getLong("creative_id");
				if (null == creativeId) {
					continue;
				}

				final List<String> platformFileIds1 = this.parseOePlatformFIleIds(creative);
				for (String platformFileId : platformFileIds1) {
					creativeMaterialList.add(new AdCreativeMaterialEntity().setAdvertiserId(advertiserId).setAdId(adId).setCreativeId(creativeId).setPlatformId(platformId).setPlatformFileId(platformFileId).setLandingPageId(landingPageId));
					platformFileIds.add(platformFileId);
				}
			}
		}

		// 构建媒体文件ID->平台素材ID的映射关系
		final Map<Pair<String, Long>, Long> materialIdMapping = this.getPlatformFileMapping(platformId, advertiserIdMapping);
		// 保存创意与素材关系信息
		this.batchSaveCreativeMaterial(creativeMaterialList, materialIdMapping, platformId);
	}

	/**
	 * 批量保存或更新腾讯广告创意与素材关系
	 *
	 * @param gdtAdList
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public void batchUpsertTxCreativeMaterial(List<GdtAd> gdtAdList) {
		if (CollectionUtils.isEmpty(gdtAdList)) {
			return;
		}
		final Integer platformId = Integer.parseInt(PlatformTypeEnum.GDT.getValue());

		final Map<Long, Set<String>> advertiserIdMapping = new HashMap<>();
		final List<AdCreativeMaterialEntity> creativeMaterialList = new ArrayList<>();

		for (GdtAd ad : gdtAdList) {
			final Long advertiserId = Long.parseLong(ad.getAccountId()), adId = ad.getAdgroupId(), creativeId = ad.getAdId();
			final Set<String> platformFileIds = advertiserIdMapping.computeIfAbsent(advertiserId, (key) -> new HashSet<>());
			final JSONObject creatives = JSON.parseObject(ad.getAdcreative());

			// 解析落地页ID
			final Long landingPageId = this.parseTxLandingPageId(creatives);

			// 解析素材ID
			final List<String> platformFileIds1 = this.parseTxPlatformFIleIds(creatives);
			for (String platformFileId : platformFileIds1) {
				creativeMaterialList.add(new AdCreativeMaterialEntity().setAdvertiserId(advertiserId).setAdId(adId).setCreativeId(creativeId).setPlatformId(platformId).setPlatformFileId(platformFileId).setLandingPageId(landingPageId));
				platformFileIds.add(platformFileId);
			}
		}

		// 构建媒体文件ID->平台素材ID的映射关系
		final Map<Pair<String, Long>, Long> platformFileMapping = this.getPlatformFileMapping(platformId, advertiserIdMapping);
		// 保存创意与素材关系信息
		this.batchSaveCreativeMaterial(creativeMaterialList, platformFileMapping, platformId);
	}

	/**
	 * 通过落地页地址解析头条落地页ID
	 *
	 * @param landingPageUrl
	 * @return
	 */
	private Long parseOeLandingPageId(String landingPageUrl) {
		if (StringUtils.isBlank(landingPageUrl)) {
			return null;
		}
		final char[] chars = landingPageUrl.toCharArray();

		boolean firstSlash = true;
		final StringBuilder pageIdStr = new StringBuilder();
		for (int i = chars.length - 1; i >= 0; --i) {
			final char c = chars[i];

			if (firstSlash && '/' != c) {
				firstSlash = false;
				pageIdStr.append(c);
			} else if ('/' != c) {
				pageIdStr.append(c);
			} else if (!firstSlash) {
				break;
			}

		}

		return 0 == pageIdStr.length() ? null : Long.parseLong(pageIdStr.reverse().toString());
	}

	/**
	 * 解析广点通落地页ID
	 *
	 * @param creatives
	 * @return
	 */
	private Long parseTxLandingPageId(JSONObject creatives) {
		final JSONObject landingObject = creatives.getJSONObject("page_spec");
		if (null != landingObject) {
			return landingObject.getLong("page_id");
		}
		return null;
	}

	/**
	 * 解析头条媒体平台素材文件ID
	 *
	 * @param creative
	 * @return
	 */
	private List<String> parseOePlatformFIleIds(JSONObject creative) {
		if (creative.containsKey("video_materials")) {
			JSONArray videoMaterials = creative.getJSONArray("video_materials");
			List<String> videoIds = new ArrayList<>();
			for (int i = 0; i < videoMaterials.size(); ++i) {
				final JSONObject creative2 = videoMaterials.getJSONObject(i);
				String videoId =  creative2.getJSONObject("video_info").getString("video_id");
				videoIds.add(videoId);
			}
			return videoIds;
		} else if (creative.containsKey("image_materials")) {
			JSONArray imageMaterials = creative.getJSONArray("image_materials");
			List<String> imageIds = new ArrayList<>();
			for (int i = 0; i < imageMaterials.size(); ++i) {
				final JSONObject creative2 = imageMaterials.getJSONObject(i);
				JSONArray imageIds2 =  creative2.getJSONArray("image_info");
				for (int j = 0; j < imageIds2.size(); ++j) {
					final JSONObject imageId2 = imageIds2.getJSONObject(i);
					String imageId = imageId2.getString("image_id");
					imageIds.add(imageId);
				}
			}
			return imageIds;
		}
		return Collections.emptyList();
	}

	/**
	 * 解析广点通媒体平台素材文件ID
	 *
	 * @param creatives
	 * @return
	 */
	private List<String> parseTxPlatformFIleIds(JSONObject creatives) {
		final JSONObject materialObject = creatives.getJSONObject("adcreative_elements");
		final String videoId, imageId;
		final JSONArray imageIds;
		if (StringUtils.isNotBlank(videoId = materialObject.getString("video"))) {
			return Collections.singletonList(videoId);
		} else if (StringUtils.isNotBlank(imageId = materialObject.getString("image"))) {
			return Collections.singletonList(imageId);
		} else if (null != (imageIds = materialObject.getJSONArray("image_list")) && !imageIds.isEmpty()) {
			return imageIds.toJavaList(String.class);
		}
		return Collections.emptyList();
	}

	/**
	 * 获取媒体平台素材文件ID到自有平台素材ID的映射
	 *
	 * @param platformId
	 * @param advertiserIdMapping
	 * @return
	 */
	private Map<Pair<String, Long>, Long> getPlatformFileMapping(Integer platformId, Map<Long, Set<String>> advertiserIdMapping) {
		final Map<Pair<String, Long>, Long> materialMapping = new HashMap<>();

		if (MapUtils.isEmpty(advertiserIdMapping)) {
			return materialMapping;
		}

		for (Map.Entry<Long, Set<String>> entry : advertiserIdMapping.entrySet()) {
			final Long advertiserId = entry.getKey();
			final Set<String> platformFileIds = entry.getValue();

			if (null == advertiserId || platformFileIds.isEmpty()) {
				continue;
			}

			final List<AdMaterialPlatform> materialPlatformList = adMaterialPlatformMapper.selectList(Wrappers.<AdMaterialPlatform>lambdaQuery()
					.select(AdMaterialPlatform::getAdvertiserId, AdMaterialPlatform::getPlatformFileId, AdMaterialPlatform::getMaterialId)
					.in(AdMaterialPlatform::getPlatformFileId, platformFileIds).eq(AdMaterialPlatform::getAdvertiserId, advertiserId).eq(AdMaterialPlatform::getPlatformId, platformId));

			for (AdMaterialPlatform materialPlatform : materialPlatformList) {
				final Pair<String, Long> key = Pair.of(materialPlatform.getPlatformFileId(), Long.parseLong(materialPlatform.getAdvertiserId()));
				final Long value = materialPlatform.getMaterialId();
				materialMapping.put(key, value);
			}

		}

		return materialMapping;
	}

	/**
	 * 批量保存和更新创意与素材关系
	 *
	 * @param creativeMaterialList
	 * @param platformFileMapping
	 * @param platformId
	 */
	private void batchSaveCreativeMaterial(List<AdCreativeMaterialEntity> creativeMaterialList, Map<Pair<String, Long>, Long> platformFileMapping, Integer platformId) {
		final Set<Long> creativeIds = new HashSet<>();
		int idx = 0;

		final Iterator<AdCreativeMaterialEntity> iterator = creativeMaterialList.iterator();
		for (AdCreativeMaterialEntity creativeMaterial; iterator.hasNext() && null != (creativeMaterial = iterator.next()); ++idx) {
			final Pair<String, Long> key = Pair.of(creativeMaterial.getPlatformFileId(), creativeMaterial.getAdvertiserId());
			final Long materialId = platformFileMapping.get(key);

			// 批量删除可能存在的旧数据
			creativeIds.add(creativeMaterial.getCreativeId());
			if (idx > 0 && 0 == idx % 1000) {
				this.remove(Wrappers.<AdCreativeMaterialEntity>lambdaQuery().in(AdCreativeMaterialEntity::getCreativeId, creativeIds).eq(AdCreativeMaterialEntity::getPlatformId, platformId));
				creativeIds.clear();
			}

			if (null != materialId) {
				creativeMaterial.setMaterialId(materialId);
			} else {
				iterator.remove();
			}
		}

		// 批量删除可能存在的旧数据
		if (!creativeIds.isEmpty()) {
			this.remove(Wrappers.<AdCreativeMaterialEntity>lambdaQuery().in(AdCreativeMaterialEntity::getCreativeId, creativeIds).eq(AdCreativeMaterialEntity::getPlatformId, platformId));
		}

		// 批量插入创意与素材关系数据
		if (!creativeMaterialList.isEmpty()) {
//			this.saveBatch(creativeMaterialList);
			for (AdCreativeMaterialEntity creativeMaterial : creativeMaterialList) {
				this.save(creativeMaterial);
			}
		}
	}


	/*@Transactional(rollbackFor = Exception.class)
	@Override
	public boolean batchSave(List<AdCreativeMaterialEntity> entityList) {
		if (CollectionUtil.isEmpty(entityList)) {
			return true;
		}
		Set<Long> creativeIds = entityList.stream().map(v -> v.getCreativeId()).collect(Collectors.toSet());
		LambdaUpdateWrapper<AdCreativeMaterialEntity> removeWrapper = Wrappers.lambdaUpdate();
		removeWrapper.in(AdCreativeMaterialEntity::getCreativeId, creativeIds);
		return this.saveBatch(entityList);
	}*/

	/*@Transactional(rollbackFor = Exception.class)
	@Override
	public boolean singleSave(AdCreativeMaterialEntity entity) {
		LambdaUpdateWrapper<AdCreativeMaterialEntity> removeWrapper = Wrappers.lambdaUpdate();
		removeWrapper.eq(AdCreativeMaterialEntity::getCreativeId, entity.getCreativeId());
		this.remove(removeWrapper);
		return this.save(entity);
	}*/

	/*private List<AdCreativeMaterialEntity> buildAdCreativeMaterialEntity(AdCreative adCreative) {
		List<AdCreativeMaterialEntity> entities = Lists.newArrayList();
		if (StringUtils.isNotBlank(adCreative.getImageIds())) {
			List<String> imgIds = JSON.parseArray(adCreative.getImageIds(), String.class);
			if (CollectionUtils.isNotEmpty(imgIds)) {
				imgIds.stream().forEach(v -> {
					entities.add(AdCreativeMaterialEntity.build(adCreative.getCreativeId(), TT_MATERIAL_FLAG, v));
				});
			}
		}
		if (StringUtils.isNotBlank(adCreative.getVideoId())) {
			entities.add(AdCreativeMaterialEntity.build(adCreative.getCreativeId(), TT_MATERIAL_FLAG, adCreative.getVideoId()));
		}
		return entities;
	}*/

	/*@Transactional(rollbackFor = Exception.class)
	@Override
	public boolean batchSaveAdCreativeMaterial(AdCreative adCreative) {
		return this.batchSave(this.buildAdCreativeMaterialEntity(adCreative));
	}*/

	/*private List<AdCreativeMaterialEntity> buildAdCreativeMaterialEntity(GdtAdCreative gdtAdCreative) {
		List<AdCreativeMaterialEntity> entities = Lists.newArrayList();
		if (StringUtils.isNotBlank(gdtAdCreative.getAdcreativeElements())) {
			JSONObject elements = JSON.parseObject(gdtAdCreative.getAdcreativeElements());
			String image = elements.getString("image");
			if (StringUtils.isNotBlank(image)) {
				entities.add(AdCreativeMaterialEntity.build(gdtAdCreative.getAdcreativeId(), GDT_MATERIAL_FLAG, image));
			}
			String video = elements.getString("video");
			if (StringUtils.isNotBlank(video)) {
				entities.add(AdCreativeMaterialEntity.build(gdtAdCreative.getAdcreativeId(), GDT_MATERIAL_FLAG, video));
			}
		}
		return entities;
	}*/

	/*@Transactional(rollbackFor = Exception.class)
	@Override
	public boolean batchSaveAdCreativeMaterial(GdtAdCreative gdtAdCreative) {
		return this.batchSave(this.buildAdCreativeMaterialEntity(gdtAdCreative));
	}*/

}
